﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using PowersourceUIToolkit;
using UCL.Powersource.Analysis;

namespace UCL.Powersource
{
    public class StatisticManagerBase : InitializedLifeCycleBase, IStatisticManager
    {


        protected StatisticManagerBase()
        {
            AvailableStatisticsList = new Dictionary<Guid, IStatistic>();
        }

        protected Dictionary<Guid, IStatistic> AvailableStatisticsList;

        public System.Collections.ObjectModel.ReadOnlyDictionary<Guid, IStatistic> AvailableStatistics { get; protected set; }

        private List<Type> _AvailableStatisticTypes;

        public IEnumerable<Type> AvailableStatisticTypes
        {
            get
            {
                if (_AvailableStatisticTypes == null)
                {
                    _AvailableStatisticTypes = new List<Type>();
                    foreach (var stat in AvailableStatisticsList.Values)
                    {
                        _AvailableStatisticTypes.Add(stat.GetType());
                    }
                }

                return _AvailableStatisticTypes;
            }
        }

        public virtual void LoadResultsFromStatisticResultsCollection(IStatisticCollectionWithResults src)
        {
            if (src == null) throw new ArgumentNullException("src", "LoadResultsFromStatisticResultsCollection was called with src==null");
            if (!IsInitialized) Initialize();
            src.Initialize();
            foreach (var it in src.Items)
            {
                if (AvailableStatistics.ContainsKey(it.Statistic_Guid))
                {
                    Debug.Assert(AvailableStatistics[it.Statistic_Guid].GetType() == it.GetType(), string.Format("Inconsistent type on deserialization. Type of statistic being replaced is {0}, type of statistic replacing is {1}", AvailableStatistics[it.Statistic_Guid].GetType().Name, it.GetType().Name));
                    AvailableStatisticsList.Remove(it.Statistic_Guid);

                    Debug.Assert(!AvailableStatistics.ContainsKey(it.Statistic_Guid), string.Format("Unable to remove statistic {0}:{1} from AvailableStatistics", it.Statistic_Guid, it.GetType().Name));
                    AvailableStatisticsList.Add(it.Statistic_Guid, it);
                }
            }
        }

        public virtual bool ResolveStatistic(Type statistic_type, ITfsTeamProjectConfiguration tfstc, ITimeFrame timeFrame, bool forceRecalculate = false)
        {
            var istat = AvailableStatistics.Values.FirstOrDefault(a => a.GetType() == statistic_type);
            if (istat == null) return false;
            istat.Resolve(tfstc, timeFrame, forceRecalculate);
            return true;
        }

        public virtual bool ResolveStatistic(Guid statistic_guid, ITfsTeamProjectConfiguration tfstc, ITimeFrame timeFrame, bool forceRecalculate = false)
        {
            var istat = AvailableStatistics.Values.FirstOrDefault(a => a.Statistic_Guid == statistic_guid);
            if (istat == null) return false;
            istat.Resolve(tfstc, timeFrame, forceRecalculate);
            return true;
        }

        public virtual bool ResolveStatistic<T>(T statistic, ITfsTeamProjectConfiguration tfstc, ITimeFrame timeFrame, bool forceRecalculate = false) where T : IStatistic
        {
            return ResolveStatistic(typeof(T), tfstc, timeFrame, forceRecalculate);
        }

        /// <summary>
        /// Default handler of initialization phase. It creates <see cref="AvailableStatistics"/>  dictionary based on <see cref="_AvailableStatisticList"/> 
        /// </summary>
        /// <returns></returns>
        protected override bool OnInitializing()
        {
            AvailableStatistics = new System.Collections.ObjectModel.ReadOnlyDictionary<Guid, IStatistic>(AvailableStatisticsList);
            
            return true;
        }
        protected override void OnDisposing()
        {
            if (StatisticManagerQueue != null) StatisticManagerQueue.Dispose();
            if (AvailableStatisticsList != null) AvailableStatisticsList.Clear();
            if (_AvailableStatisticTypes != null) _AvailableStatisticTypes.Clear();
            _AvailableStatisticTypes = null;
            AvailableStatisticsList = null;
            AvailableStatistics = null;
            return;
        }

        public IStatistic GetStatisticOrDefault(Guid uid)
        {
            if (AvailableStatistics == null) return null;
            if (!AvailableStatistics.ContainsKey(uid)) return null;
            return AvailableStatistics[uid];
        }

        public IStatistic GetStatisticOrDefault(Type statType)
        {
            if (AvailableStatistics == null) return null;
            return AvailableStatistics.FirstOrDefault(a => a.Value.GetType() == statType).Value;
        }


        public IStatistic this[Guid uid]
        {
            get { return AvailableStatistics[uid]; }
        }

        public IStatistic this[Type statType]
        {
            get { return AvailableStatistics.Values.First(a => a.GetType() == statType); }
        }

        public Type GetStatisticTypeOrDefault(Guid uid)
        {
            if (AvailableStatistics == null) return null;
            if (!AvailableStatistics.ContainsKey(uid)) return null;
            return AvailableStatistics[uid].GetType();
        }


        public bool ResolveStatistic(Type statistic, ITfsTeamProjectCollectionConfiguration tfstcc, bool forceRecalculate = false)
        {
            var retVal = true;
            foreach (var tfstc in tfstcc.Where(a => a.IsValidForStatistic))
            {
                retVal = retVal & ResolveStatistic(statistic, tfstcc, tfstc, forceRecalculate);
            }
            return retVal;
        }

        public bool ResolveStatistic(Type statistic, ITfsTeamProjectCollectionConfiguration tfstcc, ITimeFrame timeframe, bool forceRecalculate = false)
        {
            var retVal = true;
            foreach (var tfstc in tfstcc.Where(a => a.IsValidForStatistic))
            {
                retVal &= ResolveStatistic(statistic, tfstc, timeframe, forceRecalculate);
            }
            return retVal;

        }

        public bool ResolveStatistic(Type statistic, ITfsTeamProjectCollectionConfiguration tfstcc, ITfsTeamProjectConfiguration tfstc, bool forceRecalculate = false)
        {
            var retVal = true;
            foreach (var tf in tfstcc.ProjectCollectionTimeFrames)
            {
                retVal &= ResolveStatistic(statistic, tfstc, tf, forceRecalculate);
            }
            return retVal;
        }

        public void ClearStatisticsInvalidEntries(ITfsTeamProjectCollectionConfiguration teamProjCollConfig)
        {
            foreach (var stat in AvailableStatistics.Values)
            {
                stat.ClearInvalidEntries(teamProjCollConfig);
            }
        }


        private IStatisticManagerQueue _StatisticManagerQueue;
        public IStatisticManagerQueue StatisticManagerQueue
        {
            get { return _StatisticManagerQueue ?? (_StatisticManagerQueue=IoC.Get<IStatisticManagerQueue>()); }
        }
    }

    



    

}
